package com.xue.rpc.server;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.xue.rpc.common.RpcMapping;
import com.xue.rpc.protos.RPC;

/**
 * 
 * @author 北京八维博大科技 薛建新
 * @date 2022年9月3日 上午10:36:40
 * @Copyright 北京八维博大科技
 */
public class ServerMain {

	public static void main(String[] args) throws Exception {
		// 注册服务
		registeService();
		// 启动服务
		startService();
	}

	// 被调用的端点
	static record Endpoint(Object obj, Method method) {

	}

	// 被调用的端点映射
	private static final Map<String, Endpoint> endpointMap = new HashMap<>();

	private static void registeService() {
		final var math = new ServerMathImpl();
		var methods = ServerMathImpl.class.getDeclaredMethods();

		for (var m : methods) {
			RpcMapping rm = m.getDeclaredAnnotation(RpcMapping.class);
			endpointMap.put(rm.uri(), new Endpoint(math, m));
		}
	}

	private static void startService() throws Exception {
		final int port = 9999;
		try (ServerSocket server = new ServerSocket(port)) {
			System.out.println("server is started @ "+port);
			while (true) {
				// Wait for the next connection from a client
				Socket client = server.accept();
				var request = client.getInputStream();
				var response = client.getOutputStream();
				
				// serverlet和httpServlet的区别
				service(request, response);
				client.close();
			}
		}
	}

	private static void service(InputStream request, OutputStream response) throws Exception {
		// 读取请求数据
		var reqData = request.readAllBytes();
		// 解析请求
		var rpcRequest = RPC.Request.parseFrom(reqData);
		// System.out.println(rpcRequest);
		// 获取请求uri
		String uri = rpcRequest.getUri();
		// 获取请求参数
		List<Integer> argList = rpcRequest.getArgList().stream().map((RPC.Request.Arg arg) -> {
			return Integer.valueOf(arg.getValue());
		}).toList();
		// 获取将要被调用的对象
		Endpoint callObj = endpointMap.get(uri);
		// 调用实际方法并返回结果
		Integer result = (Integer) callObj.method.invoke(callObj.obj, argList.toArray());
		// 组装rpc响应
		var rpcResponse = RPC.Response.newBuilder().setType(Integer.class.toString()).setValue(String.valueOf(result))
				.build();
		// 发送数据
		response.write(rpcResponse.toByteArray());
		response.flush();
	}

}
